package cn.yshujia.filter;

import cn.yshujia.constant.SystemConst;
import cn.yshujia.domain.LoginUser;
import cn.yshujia.domain.vo.ApiVO;
import cn.yshujia.encryption.SMEncrypt;
import cn.yshujia.enums.Info;
import cn.yshujia.ex.DefineExceptionHandler;
import cn.yshujia.repository.SMRepository;
import cn.yshujia.utils.SecurityUtils;
import com.alibaba.fastjson2.JSON;
import jakarta.annotation.Resource;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletOutputStream;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;

import java.io.IOException;

/**
 * @author YShuJia
 * @create 2024/4/23
 * @description 拒绝访问处理器
 */

@Slf4j
public class PasswordAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
	
	private final AuthenticationManager authenticationManager;
	
	@Resource
	SMRepository smRepository;
	
	
	@Autowired
	public PasswordAuthenticationFilter(AuthenticationManager authenticationManager) {
		this.authenticationManager = authenticationManager;
	}
	
	public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
		String encryptedUsername = request.getParameter("username");
		String encryptedPassword = request.getParameter("password");
		String privateKey = this.smRepository.getPrivateKey();
		String username;
		String password;
		try {
			username = SMEncrypt.deSm2(privateKey, encryptedUsername);
			password = SMEncrypt.deSm2(privateKey, encryptedPassword);
		} catch (DefineExceptionHandler e) {
			throw new RuntimeException(e);
		}
		UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password);
		return this.authenticationManager.authenticate(authRequest);
	}
	
	protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response,
											FilterChain chain, Authentication authResult) throws IOException {
		response.setContentType("application/json;charset=UTF-8");
		ServletOutputStream outputStream = response.getOutputStream();
		LoginUser loginUser = (LoginUser) authResult.getPrincipal();
		String publicKey = request.getHeader(SystemConst.AUTHORITY_KEY);
		// 获取用户信息
		/*UserVO userVO = loginUser.getUser();
		String token = JwtTokenUtils.genAccessToken(userVO.getId());
		userVO.setToken(token);
		
		// 存储 token
		repository.setToken(token, userVO.getId());
		// 存储用户信息
		repository.setUser(userVO);*/
		
		UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(loginUser, null, loginUser.getAuthorities());
		authenticationToken.setDetails((new WebAuthenticationDetailsSource()).buildDetails(request));
		SecurityUtils.setAuthentication(authenticationToken);
		ApiVO<?> apiVO = null;
		try {
			apiVO = ApiVO.success(Info.NEED_DECRYPTION.getCode(), Info.NEED_DECRYPTION.getMessage(), SMEncrypt.enSm2(publicKey, "userVO"));
		} catch (DefineExceptionHandler e) {
			log.error("\n数据加密失败：{}", e.getLocalizedMessage());
		}
		outputStream.write(JSON.toJSONBytes(apiVO));
		outputStream.flush();
		outputStream.close();
	}
	
	protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) throws IOException {
		response.setContentType("application/json;charset=UTF-8");
		ServletOutputStream outputStream = response.getOutputStream();
		ApiVO<Boolean> apiVO = ApiVO.error(Info.NON_USER.getCode(), "邮箱或密码错误");
		outputStream.write(JSON.toJSONBytes(apiVO));
		outputStream.flush();
		outputStream.close();
	}
}